import React, { useEffect, useMemo, useRef } from "react";
import MindElixir from "mind-elixir";
import "mind-elixir/style.css";
import * as Y from "yjs";

// 面试官问 为什么用 Mind-elixir 而 不用ant v6 ：因为 流程图 ant v6  是后期增加需求加入的，Mind-elixir实现简单，快速，ant v6  对接成本高，接入y。js数据 实现复杂。

// 通过yText 将思维导图数据 转成JSON字符串  然后实现 字符串 级别的协同 单 个单 个字母的协同。！！！！

// 原理：1.用 Y.Text 存储整棵思维导图的 data 数据 转成 JSON 字符串 用 思维导体块  id作为key
// 2. 文档操作后 data 数据更新 然后 完整的JSON数据 通过 Y.encodeStateAsUpdate 编码更新 然后通过 Y.applyUpdate 应用更新
// 3. 监听 Ytext的 变化 ，装 字符串 转成对象 应用到 思维导图实例中 实现ui更新！！！

// JSON 转换 会消耗性能， 但思维导图 数据量小，加上一些优化措施 加上 后台 序列化 + 防抖 + 缓存  可以达到优化的目的。

// 小数据量 用 序列化+ 防抖 + 缓存实现！！  根据 阀值 大数据量 用 Worker 实现！！！！  优化 JSON 转换
// 将 JSON 转换的任务包装 异步任务 然后交给worker 处理 通过全局 版本 和  内部任务版本 只执行 最后一次 更新 解决竞态问题。！！！

// 后面实现画板 就 需要使用  最小数据级别的 协同，画板数据量大。？？？？

// 阈值建议：字符数 20k–50k，根据设备调参。
const STRINGIFY_THRESHOLD = 1;

const PARSE_THRESHOLD = 1;

export function MindMapBlockView({ block, editor }: { block: any; editor: any }) {
  const containerRef = useRef<HTMLDivElement>(null);

  const workerRef = useRef<Worker | null>(null);

  const pending = useRef(new Map<number, (v: any) => void>()); // 放置任务id 和
  // worker 返回数据的时候 将通过id 从 pending中 取出 resolve回调 将处理好的数据 传给 resolve回调 并返回
  let jobId = 1;
  const nextJobId = () => jobId++;

  useEffect(() => {
    if (!workerRef.current) {
      workerRef.current = new Worker(new URL("../worker/y-worker.ts", import.meta.url), { type: "module" });
    }
    workerRef.current.onmessage = event => {
      const { type, payload } = event.data;
      if (type === "json-stringify-result") {
        const { jobId, json } = payload;
        const resolve = pending.current.get(jobId);
        if (resolve) {
          console.log("json-stringify-result worker", json);

          resolve(json);
        }
        pending.current.delete(jobId);
      }
      if (type === "json-parse-result") {
        const { jobId, data } = payload;
        const resolve = pending.current.get(jobId);
        if (resolve) {
          console.log("json-parse-result worker", data);
          resolve(data);
        }
        pending.current.delete(jobId);
      }
    };
    return () => {
      workerRef.current?.terminate();
      workerRef.current = null;
      pending.current.clear();
    };
  }, []);

  // 将JSON 转换的任务包装 异步任务 然后交给worker 处理
  const stringifyInWorker = (data: any) => {
    return new Promise((resolve, reject) => {
      if (!workerRef.current) {
        reject(new Error("Worker not initialized"));
      } else {
        const id = nextJobId();
        pending.current.set(id, resolve);
        // 向 worker 发送任务 并设置任务id
        workerRef.current.postMessage({ type: "json-stringify", payload: { data, jobId: id } });
      }
    });
  };

  const parseInWorker = (json: string) =>
    new Promise<any>((resolve, reject) => {
      if (!workerRef.current) {
        reject(new Error("Worker not initialized"));
      } else {
        const id = nextJobId();
        pending.current.set(id, resolve);
        workerRef.current?.postMessage({ type: "json-parse", payload: { json, jobId: id } });
      }
    });

  const yText = useMemo(() => {
    const fragment = editor?.options?.collaboration?.fragment as Y.XmlFragment | undefined;
    if (!fragment) return null; // 非协同则返回 null

    const ydoc = (fragment as any).doc as Y.Doc | undefined;
    if (!ydoc) return null;

    // 每个思维导图块使用独立的 Y.Text，键名包含 block.id
    const key = `mindmap-json:${block.id}`;
    const text = ydoc.getText(key); // 获取或并创建一个共享文本
    return text;
  }, [block.id, editor]);

  useEffect(() => {
    if (!containerRef.current) {
      console.warn("思维导图容器引用为空");
      return;
    }
    const fragment = editor?.options?.collaboration?.fragment as Y.XmlFragment | undefined;
    if (!fragment) {
      console.warn("协同编辑 fragment 不存在");
      return;
    }

    const ydoc = (fragment as any).doc as Y.Doc | undefined;
    if (!ydoc) {
      console.warn("Y.Doc 不存在");
      return;
    }

    // 2.2 v5 初始化：构造 + init(data)
    let mind;
    try {
      mind = new MindElixir({
        el: containerRef.current,
        draggable: true,
        contextMenu: true,
        toolBar: true,
        editable: true
      });
      console.log("MindElixir 实例创建成功");
    } catch (error) {
      console.error("MindElixir 初始化失败:", error);
      return;
    }

    let initial: any = block.props.data || MindElixir.new("新建主题");

    // 首次优先使用协同中的整树 JSON，否则解析 props.data

    if (yText && yText.length > 0) {
      try {
        initial = JSON.parse(yText.toString());
      } catch {}
    } else if (typeof initial === "string") {
      try {
        initial = JSON.parse(initial);
      } catch {
        initial = MindElixir.new("新建主题");
      }
    }

    try {
      const err = mind.init(initial);
      console.log("MindElixir 数据初始化结果:", err);

      if (err instanceof Error) {
        console.warn("MindElixir 初始化失败，使用默认数据:", err);
        // 初始化失败时给出兜底，避免空白
        try {
          mind.init(MindElixir.new("新建主题"));
          console.log("使用默认主题初始化成功");
        } catch (fallbackError) {
          console.error("默认主题初始化也失败:", fallbackError);
          return;
        }
      }
    } catch (initError) {
      console.error("MindElixir init 调用失败:", initError);
      return;
    }

    // 2.4 防回环：区分“本地写 Y”和“远端刷 UI”
    let isLocal = false;
    const withLocal = (fn: () => void) => {
      isLocal = true;
      try {
        fn();
      } finally {
        isLocal = false;
      }
    };

    // 后台序列化 避免阻塞主线程 优化 降级采用 setTimeout 防抖
    // requestIdleCallback 浏览器空闲的时候执行
    const rIC =
      (window as any).requestIdleCallback ||
      ((cb: any, opts?: { timeout?: number }) =>
        setTimeout(() => cb({ didTimeout: true, timeRemaining: () => 0 }), opts?.timeout ?? 200));
    const cIC = (window as any).cancelIdleCallback || clearTimeout;

    let writeHandle: any = null;

    let applyHandle: any = null;

    // 2.5 本地 -> 远端：整树 JSON 覆盖（节流，避免频繁写）
    // 通过缓存避免重复写入相同字符串
    let lastSentJson = yText ? yText.toString() : "";
    let timer: any = null;

    let writeVersion = 0;

    const scheduleWrite = () => {
      // if (timer) return;
      // // 类似防抖
      // timer = setTimeout(() => {
      //   //  JSON.stringify 消耗性能 延迟 150 毫秒  再通过 mind.getData()获取150ms内的操作
      //   timer = null;
      //   if (!yText) return;
      //   const data = mind.getData();
      //   const jsonStr = JSON.stringify(data);

      //   if (jsonStr === lastSentJson) return; // 无变更则跳过

      //   editor.transact(() => {
      //     yText.delete(0, yText.length);
      //     yText.insert(0, jsonStr);

      //     // 自己改了 自己不用 应用更新 其他地方协同才需要
      //     // const update = Y.encodeStateAsUpdate(ydoc); // 编码更新
      //     // Y.applyUpdate(ydoc, update); // 应用更新
      //   }, "mindmap-local-write"); // 标记来源，便于 observe 侧识别
      //   lastSentJson = jsonStr;
      // }, 150);

      if (writeHandle) cIC(writeHandle);

      const version = ++writeVersion;

      writeHandle = rIC(
        async () => {
          if (!yText || isLocal) return;
          const data = mind.getData();
          // console.log("思维导图的全量", data);

          // 超过阀值了 则用 worker处理
          const useWorker = (lastSentJson?.length || 0) > STRINGIFY_THRESHOLD;
          const jsonStr: string = useWorker ? ((await stringifyInWorker(data)) as string) : JSON.stringify(data);

          if (version !== writeVersion) return; // 丢弃过期的版本

          if (jsonStr === lastSentJson) return; // 无变更

          editor.transact(() => {
            yText.delete(0, yText.length);
            yText.insert(0, jsonStr);
          }, "mindmap-local-write");

          lastSentJson = jsonStr;
        },
        { timeout: 300 }
      );
    };

    const onOp = () => {
      if (!yText || isLocal) return;
      scheduleWrite();
    };
    mind.bus.addListener("operation", onOp);

    // 2.6 远端 -> 本地：整树刷新 mind
    // 通过缓存避免重复解析/刷新
    let lastAppliedJson = yText ? yText.toString() : "";
    let applyVersion = 0; // 全局 总版本号 记录最新版本
    //     为什么需要
    // 连续多次操作会多次触发 stringify/parse（且可能走 Worker/idle，返回顺序不可控）。
    // 旧任务比新任务更晚返回时，可能把更旧的数据写回，造成回退/闪烁。
    // 版本号校验可防止这种“竞态条件”。
    const observer = (event?: any) => {
      if (!yText || isLocal) return;

      // 如果是自己标记的事务来源则可直接跳过（某些适配器会传递 origin）
      // 本地 触发的就跳过

      if (event && event.transaction && event.transaction.origin === "mindmap-local-write") return;

      const next = yText.toString();

      if (next === lastAppliedJson) return; // 无变化则不解析

      // try {
      //   const parsed = JSON.parse(next);
      //   withLocal(() => mind.refresh(parsed));
      //   lastAppliedJson = next;
      // } catch {}

      if (applyHandle) cIC(applyHandle);
      const version = ++applyVersion; // 任务版本号 记录自己 版本
      applyHandle = rIC(
        async () => {
          try {
            const useWorker = yText.length > PARSE_THRESHOLD;
            const parsed = useWorker ? await parseInWorker(next) : JSON.parse(next);
            if (version !== applyVersion) return; // 丢弃过期 只执行 最后一次版本！！！
            withLocal(() => mind.refresh(parsed));
            lastAppliedJson = next;
          } catch {}
        },
        { timeout: 300 }
      );
    };
    yText?.observe(observer);
    // ydoc.on("update", observer);

    // 2.7 清理
    return () => {
      mind.bus.removeListener("operation", onOp);
      yText?.unobserve(observer);
    };
  }, [block.id, yText, editor]);

  return (
    <div
      ref={containerRef}
      className="bg-white absolute z-1000"
      style={{ width: block.props.width, height: block.props.height }}
    />
  );
}
